﻿/* ********************************************************************************
 * 名称：Cpn_RepositoryService
 * 描述：企业资料表  仓储服务接口实现类（本类通过CodeSmith软件生成生成）
 * 创建人：HFL
 * 创建日期：2020-06-01 17:48:55
 * 修改人：
 * 修改日期：
 * *******************************************************************************/
using WPay.Domain.MainModule.Interface.RepositoryServices;
using WPay.Domain.Model.DTOs;
using WPay.Domain.Model.Entities;
using WPay.Infrastructure.Repository.Base;
using WPay.Infrastructure.Repository.DapperCore;
using WPay.Infrastructure.Unity;
using Dapper;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using WPay.Domain.Base;
using System.Linq.Expressions;
using WPay.Infrastructure.EFCore;
using System.Linq;
using System.Data.Entity;
using WPay.Domain;
using System.Reflection;
using Model.DTO.Manager;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace WPay.Infrastructure.Repository.MainModule
{
    /// <summary>
    ///  EF仓储基类
    /// </summary>
    public class EfCore_RepositoryService : IEfCore_RepositoryService
    {
        public Entities dataContext;
        public EfCore_RepositoryService()
        {
            dataContext = DatabaseFactory.Get();
        }
        public void Add<T>(T entity) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            dbset.Add(entity);
        }

        public void AddBatch<T>(IEnumerable<T> entities) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            dataContext.AddRange(entities);
        }

        public bool Exists<T>(ISpecification<T> specification) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            return dbset.Any(specification.SatisfiedBy());
        }

        public EntityList<T> FindAll<T>(int PageIndex, int PageSize, ISpecification<T> specification, System.Linq.Expressions.Expression<Func<T, T>> orderByExpression, bool IsDESC, bool? AsNoTracking = true, List<SortParms<T>> thenByExpression = null) where T : class, new()
        {

            var dbset = dataContext.Set<T>();
            var query = IsDESC
                                 ?
                                 dbset.Where(specification.SatisfiedBy()).OrderByDescending(orderByExpression)
                                 :
                                 dbset.Where(specification.SatisfiedBy()).OrderBy(orderByExpression);
            query = DataSort(query, thenByExpression);
            EntityList<T> pageData = new EntityList<T>();
            pageData.Data = new List<T>();
            int quyCount = query.Count();
            if (quyCount > 0)
            {
                pageData.Total = quyCount;
                int TotalPages = (int)Math.Ceiling(pageData.Total / (double)PageSize);
                pageData.Page = PageIndex < 1 ? 1 : PageIndex;
                pageData.TotalPage = TotalPages;
                if (AsNoTracking == true)
                    pageData.Data = query.Skip((pageData.Page - 1) * PageSize).Take(PageSize).AsNoTracking().ToList();
                else
                    pageData.Data = query.Skip((pageData.Page - 1) * PageSize).Take(PageSize).ToList();
            }
            return pageData;

        }
        public IEnumerable<T> GetAll<T>(bool? AsNoTracking = true) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            if (AsNoTracking == true) return dbset.AsNoTracking().ToList();
            return dbset.ToList();
        }

        public T GetByCondition<T>(ISpecification<T> specification, bool? AsNoTracking = false) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            if (AsNoTracking == false)
                return dbset.Where(specification.SatisfiedBy()).FirstOrDefault<T>();
            else return dbset.Where(specification.SatisfiedBy()).AsNoTracking().FirstOrDefault<T>();
        }

        public T GetByKey<T>(object key) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            return dbset.Find(key);
        }

        public int GetCount<T>(bool configureAwait = true) where T : class
        {
            var dbset = dataContext.Set<T>();
            return dbset.Count();
        }

        public int GetCount<T>(ISpecification<T> specification) where T : class
        {
            var dbset = dataContext.Set<T>();
            return dbset.Where(specification.SatisfiedBy()).Count();
        }

        public IEnumerable<T> GetListByTopN<S, T>(int TopN, ISpecification<T> specification, Expression<Func<T, S>> orderByExpression, bool IsDESC, bool? AsNoTracking = true, List<SortParms<T>> thenByExpression = null) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            var query = IsDESC
             ?
             dbset.Where(specification.SatisfiedBy()).OrderByDescending(orderByExpression)
             :
             dbset.Where(specification.SatisfiedBy()).OrderBy(orderByExpression);
            query = DataSort(query, thenByExpression);
            if (AsNoTracking == true) return query.Take(TopN).AsNoTracking().ToList();
            return query.Take(TopN).ToList();
        }

        public IEnumerable<T> GetMany<T>(ISpecification<T> specification, bool? AsNoTracking = true) where T : class
        {
            var dbset = dataContext.Set<T>();
            if (AsNoTracking == true) return dbset.Where(specification.SatisfiedBy()).AsNoTracking().ToList();
            return dbset.Where(specification.SatisfiedBy()).ToList();
        }
        public void LogicDelete<T>(ISpecification<T> specification) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            IEnumerable<T> objects = dbset.Where<T>(specification.SatisfiedBy()).AsEnumerable();
            foreach (dynamic obj in objects)
            {
                obj.IsDeleted = true;
            }
        }

        public void Modify<T>(T entity) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            dataContext.Entry(entity).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
        }

        public void Remove<T>(T entity) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            dbset.Remove(entity);
        }
        public void RemoveRange<T>(List<T> entity) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            dbset.RemoveRange(entity);
        }
        public void Remove<T>(ISpecification<T> specification) where T : class, new()
        {
            var dbset = dataContext.Set<T>();
            IEnumerable<T> objects = dbset.Where<T>(specification.SatisfiedBy()).AsEnumerable();
            foreach (dynamic obj in objects)
            {
                dbset.Remove(obj);
            }
        }

        public void Update<T>(T entity, params Expression<Func<T, object>>[] properties) where T : class, new()
        {
            dataContext.AttachUpdated(entity);
            var entry = dataContext.Entry(entity);
            foreach (var selector in properties)
            { entry.Property(selector).IsModified = true; }

        }


        public static IOrderedQueryable<M> DataSort<M>(IQueryable<M> source, List<SortParms<M>> thenByExpression) where M : class, new()
        {
            if (thenByExpression == null)
                return (IOrderedQueryable<M>)source;
            var type = typeof(M);
            thenByExpression.ForEach(x =>
            {
                var sortingDir = !x.ISDESC ? "ThenBy" : "ThenByDescending";
                var property = GetPropertyInfo(x.Func);
                var param = Expression.Parameter(type, property.Name);
                var pi = type.GetProperty(property.Name);
                Type[] types = new Type[2];
                types[0] = type;
                types[1] = pi.PropertyType;
                var expr = Expression.Call(typeof(Queryable), sortingDir, types, source.Expression, Expression.Lambda(Expression.Property(param, property.Name), param));
                source = source.AsQueryable().Provider.CreateQuery<M>(expr);
            });
            return (IOrderedQueryable<M>)source;
        }
        public IOrderedQueryable<M> DataSort<M>(IQueryable<M> source, Dictionary<string, string> sort) where M : class, new()
        {
            if (!sort.Any())
                return (IOrderedQueryable<M>)source;
            var type = typeof(M);
            var sortingDir = sort.Values.FirstOrDefault() == "ASC" ? "OrderBy" : "OrderByDescending";
            var property = type.GetProperties().FirstOrDefault(x => x.Name == sort.Keys.FirstOrDefault());
            var param = Expression.Parameter(type, property.Name);
            var pi = type.GetProperty(property.Name);
            Type[] types = new Type[2];
            types[0] = type;
            types[1] = pi.PropertyType;
            var expr = Expression.Call(typeof(Queryable), sortingDir, types, source.Expression, Expression.Lambda(Expression.Property(param, property.Name), param));
            source = source.AsQueryable().Provider.CreateQuery<M>(expr);
            if (sort.Count > 1)
            {
                var index = 0;
                sort.ToList().ForEach(x =>
                {
                    if (index != 0)
                    {
                        sortingDir = x.Value == "ASC" ? "ThenBy" : "ThenByDescending";
                        property = type.GetProperties().FirstOrDefault(y => y.Name == x.Key);
                        param = Expression.Parameter(type, property.Name);
                        pi = type.GetProperty(property.Name);
                        types = new Type[2];
                        types[0] = type;
                        types[1] = pi.PropertyType;
                        expr = Expression.Call(typeof(Queryable), sortingDir, types, source.Expression,
                            Expression.Lambda(Expression.Property(param, property.Name), param));
                        source = source.AsQueryable().Provider.CreateQuery<M>(expr);
                    }
                    index++;
                });
            }
            return (IOrderedQueryable<M>)source;
        }
        public static PropertyInfo GetPropertyInfo<M>(Expression<Func<M, dynamic>> select)
        {
            var body = select.Body;
            if (body.NodeType == ExpressionType.Convert)
            {
                var o = ((UnaryExpression)body).Operand;
                return ((MemberExpression)o).Member as PropertyInfo;
            }
            else if (body.NodeType == ExpressionType.MemberAccess)
            {
                return ((MemberExpression)body).Member as PropertyInfo;
            }
            return null;
        }

        public Entities DbContext()
        {
            //return dataContext ?? (dataContext = DatabaseFactory.Get());
            return DatabaseFactory.Get();
        }
        public EntityList<M> FindAllAsQuery<M>(IQueryable<M> query, int PageIndex, int PageSize, bool? AsNoTracking = true, List<SortParms<M>> thenByExpression = null) where M : class, new()
        {
            EntityList<M> pageData = new EntityList<M>();
            pageData.Data = new List<M>();
            int quyCount = query.AsEnumerable().Count();
            if (quyCount > 0)
            {
                pageData.Total = quyCount;
                int TotalPages = (int)Math.Ceiling(pageData.Total / (double)PageSize);
                pageData.TotalPage = TotalPages;
                pageData.Page = PageIndex < 1 ? 1 : PageIndex;
                pageData.Data = AsNoTracking == true ? query.Skip((pageData.Page - 1) * PageSize).Take(PageSize).AsNoTracking().ToList() : query.Skip((pageData.Page - 1) * PageSize).Take(PageSize).ToList();
            }
            return pageData;
        }
        public EntityList<M> FindAllAsQueryExport<M>(IQueryable<M> query, int PageIndex, int PageSize, bool? AsNoTracking = true, List<SortParms<M>> thenByExpression = null) where M : class, new()
        {
            EntityList<M> pageData = new EntityList<M>();
            pageData.Data = new List<M>();
            int quyCount = query.AsEnumerable().Count();
            if (quyCount > 0)
            {
                pageData.Total = quyCount;
                pageData.Data = AsNoTracking == true ? query.AsNoTracking().ToList() : query.ToList();
            }
            return pageData;
        }
        public bool SaveChanges()
        {
            return dataContext.SaveChanges() > 0;
        }
        public void Dispose()
        {
            dataContext.Dispose();
        }
        public async Task<bool> SaveChangesAsync()
        {
            return await dataContext.SaveChangesAsync() > 0;
        }
        ///// <summary>
        ///// 获取redis登录信息
        ///// </summary>
        ///// <returns></returns>
        //public static LoginUserDTO InitSession(HttpContext httpContext)
        //{
        //    var tokenStr = httpContext.Request.Headers["Authorization"];
        //    TokenModel tm = ((TokenModel)RayPIMemoryCache.Get(tokenStr));
        //    var dto = Newtonsoft.Json.JsonConvert.DeserializeObject<LoginUserDTO>(tm.UserJson);
        //    if (dto == null)
        //    {
        //        dto = new LoginUserDTO();
        //        dto.DefActionList = new List<RoleAction_ModuleDTO>();
        //        dto.UserActionList = new List<RoleActionDTO>();
        //    }
        //    return dto;
        //}
        public EntityList<T> FindAllAsQueryPage<T>(IQueryable<T> query, int PageIndex, int PageSize) where T : class, new()
        {
            EntityList<T> pageData = new EntityList<T>();
            pageData.Data = new List<T>();
            int quyCount = query.Count(x => true);
            if (quyCount > 0)
            {
                pageData.Total = quyCount;
                int TotalPages = (int)Math.Ceiling(pageData.Total / (double)PageSize);
                pageData.Page = PageIndex < 1 ? 1 : PageIndex;
                pageData.TotalPage = TotalPages;
                pageData.Data = query.Skip((pageData.Page - 1) * PageSize).Take(PageSize).ToList();
            }
            return pageData;

        }
    }
}
